package com.bitbakery.plugin.cl.lang;

import com.bitbakery.plugin.cl.lang.lexer.CLTokenTypes;
import com.bitbakery.plugin.cl.lang.psi.CLDefmacro;
import com.bitbakery.plugin.cl.lang.psi.CLDefun;
import com.bitbakery.plugin.cl.lang.psi.CLElementTypes;
import com.intellij.lang.ASTNode;
import com.intellij.lang.folding.FoldingBuilder;
import com.intellij.lang.folding.FoldingDescriptor;
import com.intellij.openapi.editor.Document;
import com.intellij.psi.PsiElement;

import java.util.ArrayList;
import java.util.List;

public class CLFoldingBuilder implements FoldingBuilder {
    public FoldingDescriptor[] buildFoldRegions(ASTNode node, Document document) {
        weirdHack(node);
        List<FoldingDescriptor> descriptors = new ArrayList<FoldingDescriptor>();
        appendDescriptors(node, document, descriptors);
        return descriptors.toArray(new FoldingDescriptor[descriptors.size()]);
    }
    private void weirdHack(ASTNode node) {
        // We have to touch the PSI tree to get the folding to show up when we first open a file
        if (node.getElementType() == CLElementTypes.FILE) {
            final PsiElement firstChild = node.getPsi().getFirstChild();
        }
    }

    private void appendDescriptors(final ASTNode node, final Document document, final List<FoldingDescriptor> descriptors) {
        if (isFoldableNode(node)) {
            descriptors.add(new FoldingDescriptor(node, node.getTextRange()));
        }

        ASTNode child = node.getFirstChildNode();
        while (child != null) {
            appendDescriptors(child, document, descriptors);
            child = child.getTreeNext();
        }
    }

    private boolean isFoldableNode(ASTNode node) {
        return (node.getElementType() == CLElementTypes.FUNCTION_DEFINITION)
                || (node.getElementType() == CLElementTypes.MACRO_DEFINITION)
                || (node.getElementType() == CLTokenTypes.BLOCK_COMMENT);
    }

    public String getPlaceholderText(ASTNode node) {
        if (node.getElementType() == CLElementTypes.FUNCTION_DEFINITION) {
            CLDefun def = (CLDefun) node.getPsi();
            return "(defun " + def.getName() + "...)";
        } else if (node.getElementType() == CLElementTypes.MACRO_DEFINITION) {
            CLDefmacro def = (CLDefmacro) node.getPsi();
            return "(defmacro " + def.getName() + "...)";
        } else if (node.getElementType() == CLTokenTypes.BLOCK_COMMENT) {
            return node.getText().substring(0, 25) + "...";
        }
        return null;
    }

    public boolean isCollapsedByDefault(ASTNode node) {
        return false;
    }
}
